package com.shhic.hhplt.server.facade;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import com.mongodb.client.FindIterable;
import com.shhic.hhplt.server.exceptions.RequestParamException;
import com.shhic.hhplt.server.service.ITestReportService;
import lombok.extern.slf4j.Slf4j;
import org.bson.Document;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import com.shhic.hhplt.server.biz.ITestReportHelper;
import com.shhic.hhplt.server.biz.IWorkbayStateBuffer;
import com.shhic.hhplt.server.exceptions.TestReportXmlException;
import com.shhic.hhplt.server.model.CommonRtnString;
import com.shhic.hhplt.server.model.CommonRtnValue;
import com.shhic.hhplt.server.model.NoPayload;
import com.shhic.hhplt.server.model.ProductBindingCode;
import com.shhic.hhplt.server.model.ProductBindingCodeQuery;
import com.shhic.hhplt.server.model.ProductSuite;
import com.shhic.hhplt.server.model.ProductSuiteQuery;
import com.shhic.hhplt.server.model.ProductTestResult;
import com.shhic.hhplt.server.model.ProductTestStatus;
import com.shhic.hhplt.server.model.TestResultEnum;
import com.shhic.hhplt.server.service.ITestReportXmlPersist;
import com.shhic.hhplt.testreport.TestReport;

@Controller
@Slf4j
public class TestingResultController {

    @Resource
    ITestReportHelper testReportHelper;
    @Autowired
    ITestReportService trService;
    @Resource
    ITestReportXmlPersist testReportXmlPersist;
    @Resource
    IWorkbayStateBuffer workbayStateBuffer;


    private static Object bindingCodeSynObj = new Object();    //绑定码逻辑同步块

    /**
     * 根据产品测试中的条码，获得产品唯一标识
     *
     * @param productName 产品名称
     * @param suiteName   测试用例名，可空。如果为空，则加载首先匹配的标识码；当测试中只存在一种条码的时候，或条码不重复时，可以使用之。
     * @param barCode     条码
     * @return
     */
    @RequestMapping(value = "/getProductIdCodeByTestSuiteBarCode.do", method = RequestMethod.POST)
    @ResponseBody
    public CommonRtnValue<CommonRtnString> getProductIdCodeByTestSuiteBarCode(@RequestParam String productName, @RequestParam String suiteName, @RequestParam String barCode) {
        ProductSuiteQuery q = new ProductSuiteQuery();
        q.setBarCode(barCode);
        q.setProductName(productName);
        q.setSuiteName(suiteName.equals("") ? null : suiteName);
        q.setStartDate(0);
        q.setEndDate(new Date().getTime());
        List<ProductSuite> psl = trService.queryProductSuite(q);
        if (psl == null || psl.isEmpty()) {
            return new CommonRtnValue<CommonRtnString>(1, "没找到对应的产品");
        }
        ProductSuite productSuite = psl.get(0);
        return new CommonRtnValue<CommonRtnString>(new CommonRtnString(productSuite.getIdCode()));
    }

    /**
     * 根据产品绑定码，获得唯一标识码
     *
     * @param productName
     * @param codeName
     * @param code
     * @return
     */
    @RequestMapping(value = "/getProductIdCodeByBindingCode.do", method = RequestMethod.POST)
    @ResponseBody
    public CommonRtnValue<CommonRtnString> getProductIdCodeByBindingCode(@RequestParam String productName, @RequestParam String codeName, @RequestParam String code) {
        ProductBindingCode bindingCode = trService.getProductBindingCode(productName, codeName, code);
        return bindingCode == null ?
                new CommonRtnValue<CommonRtnString>(1, String.format("没找到%s为%s的%s产品", codeName, code, productName)) :
                new CommonRtnValue<CommonRtnString>(new CommonRtnString(bindingCode.getIdCode()));
    }


    /**
     * 通过属性键值，查询出所有关联的idCode
     *
     * @param bindingCode 中只有idCode,codeName,code存在
     *                    url：/HHPLTServer/findAllIdCodeByCode.do
	 *                    method: post
	 *                    Header: Content-type: application/json
     *                    body：{"productName":"CPC卡片","codeName":"卡号","code":0}
	 *
	 * @return 返回结果解析    rtnCode:0(成功)，1(结果未找到)，400(请求参数错误)，500(服务器异常)
	 * 						  payload:(0,[123,123,....]),(1,null),(400,null),(500,null)
     */
    @RequestMapping(value = "/findAllIdCodeByCode.do", method = RequestMethod.POST)
    @ResponseBody
    public CommonRtnValue<List<String>> findAllIdCodeByCode(@RequestBody ProductBindingCode bindingCode) {
        try {
            List<String> idCodes = trService.findAllIdCodeByCode(bindingCode);
            if (idCodes != null) {
                return new CommonRtnValue<>(idCodes);
            } else {
                return new CommonRtnValue<>(1, String.format("没找到%s为%s的%s产品", bindingCode.getCodeName(),
                        bindingCode.getCode(), bindingCode.getProductName()));
            }
        }catch (RequestParamException e){
        	return new CommonRtnValue<>(400,"参数不完整");
		} catch (Exception e) {
            e.printStackTrace();
            return new CommonRtnValue<>(500, "服务器异常");
        }
    }


    /**
     * 获得产品测试状态
     *
     * @param productName 产品名称
     * @param idCode      产品标识码
     * @return 产品测试状态对象，里面是每个测试项的状态
     */
    @RequestMapping(value = "/getProductTestStatus.do", method = RequestMethod.POST)
    @ResponseBody
    public CommonRtnValue<ProductTestStatus> getProductTestStatus(@RequestParam String productName, @RequestParam String idCode) {
        List<ProductSuite> psl = trService.getProductTestStatusList(productName, idCode);
        if (psl.isEmpty()) {
            return new CommonRtnValue<ProductTestStatus>();
        }
        ProductTestStatus ps = new ProductTestStatus();
        ps.setIdCode(idCode);
        ps.setProductName(productName);
        ps.setResult(trService.getProductTestResult(productName, idCode).getResult());
        Map<String, TestResultEnum> ss = new HashMap<String, TestResultEnum>();
        for (ProductSuite p : psl) {
            ss.put(p.getSuiteName(), p.getResult());
        }
        ps.setSuiteStatus(ss);

        return new CommonRtnValue<ProductTestStatus>(ps);
    }

    /**
     * 上传测试报告
     *
     * @param testReport
     * @return
     */
    @RequestMapping(value = "/uploadTestingReport.do", method = RequestMethod.POST)
    @ResponseBody
    public CommonRtnValue<NoPayload> uploadTestingReport(@RequestBody String testReport) {
        log.info("上传的报告{}", testReport);
        try {
            TestReport uploadedReport = testReportHelper.generateTestReportFromXml(testReport);
            workbayStateBuffer.notifyTestReport(uploadedReport);
            String idCode = uploadedReport.getTestingProduct().getIdCode();
            String productName = uploadedReport.getTestingProduct().getProductName();

            ProductTestResult oriProductTestResput = trService.getProductTestResult(productName, idCode);

            String reportLoc = oriProductTestResput == null ?
                    testReportXmlPersist.generateNewReportLoc(productName, idCode) : oriProductTestResput.getReportLoc();
            TestReport toPersistReport = null;

            if (oriProductTestResput == null) {
                //以前没有报告，直接保存这次的
                toPersistReport = uploadedReport;
                ProductTestResult p = testReportHelper.generateProductTestResult(uploadedReport);
                p.setReportLoc(reportLoc);
                insertProductTestResult(p);
            } else {//以前存在报告，拼装后保存
                TestReport oriReport = testReportXmlPersist.getTestReport(reportLoc);
                toPersistReport = testReportHelper.mergeReport(oriReport, uploadedReport);
            }
            persistTestReport(toPersistReport, reportLoc);
            persistProductSuite(uploadedReport);    //保存测试结果集


            return new CommonRtnValue<NoPayload>();
        } catch (TestReportXmlException e) {
            log.error(null, e);
            return new CommonRtnValue<NoPayload>(1, e.getMessage());
        }
    }

    private void insertProductTestResult(ProductTestResult p) {
        trService.insertProductTestResult(p);
    }

    /**
     * 标记产品测试成功完成
     * 没有标记失败的接口，只要有一个测试项不通过，整体就失败了
     *
     * @param productName
     * @param idCode
     * @return
     */
    @RequestMapping(value = "/markTestingProductFinishSuccessfully.do", method = RequestMethod.POST)
    @ResponseBody
    public CommonRtnValue<NoPayload> markTestingProductFinishSuccessfully(@RequestParam String productName, @RequestParam String idCode) {
        trService.updateProductTestResultSucc(productName, idCode);
        return new CommonRtnValue<NoPayload>();
    }

    //保存报告
    private void persistTestReport(TestReport report, String persistLocation) throws TestReportXmlException {
        testReportXmlPersist.saveOrUpdateReportXml(report, persistLocation);
    }


    //保存测试集合结果，处理绑定标识码
    private void persistProductSuite(TestReport report) {
        ProductTestResult p = testReportHelper.generateProductTestResult(report);
        List<ProductSuite> ptsList = testReportHelper.generateProductTestStatusList(report);
        trService.insertProductSuite(p, ptsList);

        List<ProductBindingCode> pbcl = testReportHelper.generateBindingCodeList(report);
        if (!pbcl.isEmpty()) {
            trService.insertProductBindingCode(pbcl);
        }
    }

    /**
     * 检查并持久唯一绑定码
     * 检查需要持久的绑定码是否唯一，如果唯一，直接持久化之并返回成功；
     * 如果发现绑定码已经存在，则不持久并返回失败
     *
     * @param productName     产品名称
     * @param idCode          产品标识码
     * @param bindingCodeName 绑定码类型
     * @param code            绑定码值
     * @return
     */
    @RequestMapping(value = "/checkAndPersistUniqueBindingCode.do", method = RequestMethod.POST)
    @ResponseBody
    public CommonRtnValue<NoPayload> checkAndPersistUniqueBindingCode(@RequestParam String productName,
                                                                      @RequestParam String idCode, @RequestParam String bindingCodeName, @RequestParam String code) {

        ProductBindingCodeQuery query = new ProductBindingCodeQuery();
        query.setProductName(productName);
        query.setCodeName(bindingCodeName);
        query.setCode(code);

        ProductBindingCode pbc = new ProductBindingCode();
        pbc.setBindingTime(System.currentTimeMillis());
        pbc.setCode(code);
        pbc.setCodeName(bindingCodeName);
        pbc.setIdCode(idCode);
        pbc.setProductName(productName);

        synchronized (bindingCodeSynObj) {
            List<ProductBindingCode> existedCodeList = trService.queryBindingCode(query);
            if (existedCodeList == null || existedCodeList.isEmpty()) {
                trService.insertProductBindingCode(pbc);
                return new CommonRtnValue<NoPayload>();
            } else if (existedCodeList.size() > 1) {
                return new CommonRtnValue<NoPayload>(2, "绑定码已存在");
            } else {
                ProductBindingCode productBindingCode = existedCodeList.get(0);
                if (productBindingCode.getIdCode().equals(idCode)) {
                    return new CommonRtnValue<NoPayload>();
                } else {
                    return new CommonRtnValue<NoPayload>(1, "绑定码已存在");
                }
            }
        }
    }

    /**
     * 获得绑定码值
     *
     * @param productName     产品
     * @param idCode          标识码
     * @param bindingCodeName 绑定码名称
     * @return 返回绑定码值，如果没有，返回空字符串
     */
    @RequestMapping(value = "/getBindingCode.do", method = RequestMethod.POST)
    @ResponseBody
    public CommonRtnValue<CommonRtnString> getBindingCode(@RequestParam String productName,
                                                          @RequestParam String idCode, @RequestParam String bindingCodeName) {
        List<ProductBindingCode> queryBindingCode;
        synchronized (bindingCodeSynObj) {
            ProductBindingCodeQuery query = new ProductBindingCodeQuery();
            query.setIdCode(idCode);
            query.setCodeName(bindingCodeName);
            query.setProductName(productName);
            query.setLimit(1);
            queryBindingCode = trService.queryBindingCode(query);
        }
        if (queryBindingCode == null || queryBindingCode.isEmpty()) {
            return new CommonRtnValue<CommonRtnString>(new CommonRtnString(""));
        } else {
            return new CommonRtnValue<CommonRtnString>(new CommonRtnString(queryBindingCode.get(0).getCode()));
        }
    }

    /**
     * 取消某个产品系列中的一个产品
     *
     * @param productName 产品名称
     * @param idCode      标识码
	 *                    url: /HHPLTServer/unbindCode.do?productName=cpc&idCode=123
	 *                    method: Get
     * @return 返回结果解析  (0,成功,null) (1,异常信息)
     */
    @RequestMapping(value = "/unbindCode.do")
    @ResponseBody
    public CommonRtnValue<NoPayload> unbindCode(@RequestParam String productName,
                                                @RequestParam String idCode) {
        ProductBindingCode pbc = new ProductBindingCode();
        pbc.setProductName(productName);
        pbc.setIdCode(idCode);
        try {
            trService.lostGroupBindingCode(pbc);
            return new CommonRtnValue<NoPayload>();
        } catch (Exception e) {
            e.printStackTrace();
            return new CommonRtnValue<NoPayload>(1, e.getMessage());
        }
    }

    /**
     * 获取所有属性
     *
     * @param idCode 标识码
     */
    @GetMapping(value = "/all_binding_code")
    @ResponseBody
    public CommonRtnValue<Document> getBindingCode(@RequestParam String idCode) {
        Document result = null;
        try {
            result = trService.getBindingCodeByPI(idCode);
        } catch (RuntimeException e) {
            return new CommonRtnValue<>(1, e.getMessage());
        }
        return new CommonRtnValue<>(result);
    }
}
